﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Jint.Delegates;
using Jint.Native;
using Jint.Debugger;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace Dynamo
{


    public class DNNJintEngine
    {

        private bool debug = false;
        public bool Debug
        {
            get { return debug; }
            set
            {
                debug = value;
                if(JintEngine!=null) JintEngine.SetDebugMode(value);
            }
        }

        public DNNJintEngine(System.Web.UI.Control Host, System.Web.UI.Page Page, DotNetNuke.Entities.Modules.PortalModuleBase Parent)
        {
            this.Host = Host;
            Controller = new DotNetNuke.Entities.Modules.ModuleController();
            JintEngine = new Jint.JintEngine();            
            
            Twitter t = new Twitter();
            DataContext = new DataContext();
            this.Request = System.Web.HttpContext.Current.Request;
            this.Page = Page;
            this.Server = System.Web.HttpContext.Current.Server;
            this.Parent = Parent;           
            this.Server = Server;


            JintEngine.SetParameter("ModuleController", Controller);
            JintEngine.SetParameter("DataContext", DataContext);
            JintEngine.SetParameter("Parent", Host);
            JintEngine.SetParameter("Twitter", t);

            if ((Host.Parent.Parent as System.Web.UI.UpdatePanel) != null)
            {
                JintEngine.SetParameter("UpdatePanel", Host.Parent.Parent);
            }

            JintEngine.SetParameter("this", this.Parent);
            
            JintEngine.SetParameter("Request", this.Request);
            JintEngine.SetParameter("Page", this.Page);
            JintEngine.SetParameter("User", this.Page.User.Identity);
            JintEngine.SetParameter("UserInfo", Parent.UserInfo);
            JintEngine.SetParameter("Server", this.Server);
            
            JintEngine.SetFunction("ExecuteSql", new Jint.Delegates.Func<string, System.Data.SqlClient.SqlDataReader>(a => { return DataContext.Execute(a); }));
            JintEngine.SetFunction("GetSqlValue", new GetSqlValue(SqlValue));
            JintEngine.SetFunction("RawWrite", new Writer(Write));
            JintEngine.SetFunction("echo", new AppendText(Append));
            
            JintEngine.SetFunction("css", new AddCssDelegate(AddCss));
            JintEngine.SetFunction("style", new InlineCssDelegate(InlineCss));
            
            JintEngine.SetFunction("js", new AddJSDelegate(AddJS));
            JintEngine.SetFunction("path", new MapPathDelegate(MapPath));
            JintEngine.SetFunction("ReadFile", new ReadFileDelegate(ReadFile));
            JintEngine.SetFunction("include", new IncludeDelegate(Include));
            JintEngine.SetFunction("RenderFile", new RenderFileDelegate(RenderFile));
            JintEngine.SetFunction("form", new RequestVarDelegate(RequestVar));
            JintEngine.SetFunction("get", new RequestVarDelegate(RequestVar));
            JintEngine.SetFunction("q", new RequestVarDelegate(RequestVar));
            JintEngine.SetFunction("isNull", new isNullDelegate(isNull));


            JintEngine.SetFunction("cacheGet", new CacheGetDelegate(CacheGet));
            JintEngine.SetFunction("cacheAdd", new CacheAddDelegate(CacheAdd));
            JintEngine.SetFunction("cacheRemove", new CacheRemoveDelegate(CacheRemove));

            JintEngine.SetFunction("load", new Action<string>(s => { System.Reflection.Assembly.Load(s); }));
            JintEngine.SetFunction("loadfrom", new Action<string>(s => { System.Reflection.Assembly.LoadFrom(s); }));

            //debugging            
            JintEngine.SetFunction("trace", new Action<string>(s => { System.Diagnostics.Trace.WriteLine(s); }));
            
            //security
            JintEngine.AllowClr = AdminPermissions.AllowCLR;

            if (Dynamo.AdminPermissions.IgnoreSecurity)
                JintEngine.DisableSecurity();
            else
            {
                JintEngine.EnableSecurity();
                string list = Dynamo.AdminPermissions.EnabledPermissions;
                string[] items = list.Split(';');
                foreach (string s in items)
                {
                    if (s != "")
                    {
                        foreach (Type type in Dynamo.AdminPermissions.IPermissionTypeList)
                        {
                            if (s == type.Name)
                            {
                                System.Security.IPermission p = (type.Assembly.CreateInstance(type.FullName, false, System.Reflection.BindingFlags.CreateInstance, null, new object[] { System.Security.Permissions.PermissionState.Unrestricted }, System.Threading.Thread.CurrentThread.CurrentCulture, null) as System.Security.IPermission);
                                if (p != null)
                                {                                    
                                    JintEngine.AddPermission(p);
                                }
                                break;
                            }
                        }
                    }
                }
            }

        }

        public HttpRequest Request { get; set; }
        public System.Web.UI.Page Page { get; set; }
        public HttpServerUtility Server { get; set; }
        public DotNetNuke.Entities.Modules.PortalModuleBase Parent { get; set; }


        public delegate void CacheAddDelegate(string key, object value, double minutes);
        public void CacheAdd(string key, object value, double minutes)
        {
            Page.Cache.Add(key, value, null, DateTime.Now.AddMinutes(minutes), TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Normal, null);
        }
        public delegate void CacheRemoveDelegate(string key);
        public void CacheRemove(string key)
        {
            Page.Cache.Remove(key);
        }
        public delegate object CacheGetDelegate(string key);
        public object CacheGet(string key)
        {
            return Page.Cache.Get(key);
        }


        public delegate bool isNullDelegate(object value);
        public bool isNull(object value)
        {
            return (value == null);
        }


        private System.Text.StringBuilder inlineSB = new System.Text.StringBuilder();
        public string Run(string Script)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            List<CodeBlock> blocks = CodeBlock.ProcessScriptToCodeBlocks(Script);

            foreach (CodeBlock b in blocks.OrderBy(x => x.Order).ToList())
            {
                if (b.CodeBlockType == CodeBlockType.Html)
                    sb.Append(b.Script);
                else
                {
                    try
                    {
                        object result = JintEngine.Run(b.Script, true);                        
                        if (inlineSB != null && inlineSB.ToString().Trim() != "") sb.Append(inlineSB.ToString());
                        inlineSB = new System.Text.StringBuilder();
                        if (result != null && result.ToString().Trim() != "") sb.Append(result.ToString().Trim());
                    }
                    catch (Exception e)
                    {
                        if (Parent.UserInfo.IsSuperUser)
                        {
                            sb.Append(e.ToString());
                        }
                        else
                        {
                            break;
                        }
                    }

                }
            }
            return sb.ToString();
       }

        public System.Web.UI.Control Host { get; set; }
        public DotNetNuke.Entities.Modules.ModuleController Controller { get; set; }
        public Jint.JintEngine JintEngine { get; set; }
        public DataContext DataContext { get; set; }

        
        public delegate string GetSqlValue(System.Data.SqlClient.SqlDataReader rdr, double fld);
        public string SqlValue(System.Data.SqlClient.SqlDataReader rdr, double fld)
        {
            return rdr[(int)fld].ToString();
        }
        public delegate void InlineCssDelegate(string CSS);
        public void InlineCss(string CSS)
        {
            Page.Header.Controls.Add(new System.Web.UI.LiteralControl("<style>" + CSS + "</style>"));
        }

        public delegate void AddCssDelegate(string CSS);
        public void AddCss(string CSS)
        {
            Page.Header.Controls.Add(new System.Web.UI.LiteralControl("<link href=\"" + CSS + "\" rel=\"stylesheet\" type=\"text/css\" media=\"screen\"/>"));
        }
        public delegate void AddJSDelegate(string Url);
        public void AddJS(string Url)
        {
            Page.Header.Controls.Add(new System.Web.UI.LiteralControl("<script type=\"text/javascript\" src=\"" + Url + "\" ></script>"));
        }


        public delegate string MapPathDelegate(string Path);
        public string MapPath(string Path)
        {
            return Server.MapPath(Path);
        }



        public delegate string RequestVarDelegate(string VariableName);
        public string RequestVar(string VariableName)
        {
            string value = Request[VariableName];
            if(value !=null && value!="")  return Request[VariableName];
            return "";
        }

        
        public delegate string ReadFileDelegate(string Path);
        public string ReadFile(string Path)
        {
            return System.IO.File.ReadAllText(Path);
        }


        public delegate void Writer(string Input);
        public void Write(string Input)
        {
            
            System.Web.HttpContext.Current.Response.Write(Input);
        }


        public delegate void IncludeDelegate(string Path);
        public void Include(string Path)
        {
            if (System.IO.File.Exists(Path))
            {
                this.Run(System.IO.File.ReadAllText(Path)).ToString();
            }
        }

        public delegate object RenderFileDelegate(string Path);
        public string RenderFile(string Path)
        {
            string result = "File not found";
            if (System.IO.File.Exists(Path))
            {
                result = this.Run(System.IO.File.ReadAllText(Path)).ToString();
            }
            return result;
        }

        public delegate void AppendText(object Input);
        public void Append(object Input)
        {
            if (Input != null && Input.ToString().Trim() != "")
                inlineSB.Append(Input.ToString().Trim());
            
        }

        public static string ConvertUrlsToLinks(string msg)
        {
            if (msg != null && msg.Trim() != "")
            {
                string regex = @"((www\.|(http|https|ftp|news|file)+\:\/\/)[&#95;.a-z0-9-]+\.[a-z0-9\/&#95;:@=.+?,##%&~-]*[^.|\'|\# |!|\(|?|,| |>|<|;|\)])";
                Regex r = new Regex(regex, RegexOptions.IgnoreCase);
                return r.Replace(msg, "<a href=\"$1\" title=\"Click to open in a new window or tab\" target=\"&#95;blank\">$1</a>").Replace("href=\"www", "href=\"http://www");
            }
            else return "";
        }

    }
}